/* 
 * File:   VisibleStackSizeParameterCommand.cpp
 * Author: Gab'z
 * 
 * Created on 5 juin 2012, 15:15
 */

#include "VisibleStackSizeParameterCommand.h"
#include "../../Context.h"
#include "exception/MementoException.h"
#include "model/memento/VisibleStackSizeParameterMemento.h"

namespace calculator {

    VisibleStackSizeParameterCommand::VisibleStackSizeParameterCommand(const std::string name) : ParametersCommand(name) {
    }

    VisibleStackSizeParameterCommand::VisibleStackSizeParameterCommand(const VisibleStackSizeParameterCommand& orig) : ParametersCommand(orig._name) {
    }

    VisibleStackSizeParameterCommand::~VisibleStackSizeParameterCommand() {
    }

    VisibleStackSizeParameterCommand* VisibleStackSizeParameterCommand::clone() const {
        return new VisibleStackSizeParameterCommand(_name);
    }

    std::string VisibleStackSizeParameterCommand::isExecutable() const {
        // le premier nombre de la pile doit être un entier,
        if (Context::getInstance()->getCurrentStack()->size() == 0) return "Empty stack";
        if (dynamic_cast<const Integer*> (Context::getInstance()->getCurrentStack()->top()) == 0) return "Stack top must be an Integer";
        return "";
    }

    void VisibleStackSizeParameterCommand::execute() const throw (CommandException) {
        if (Context::getInstance()->getCurrentStack()->size() == 0) throw CommandException("Empty stack");
        const Integer* integer = dynamic_cast<const Integer*> (Context::getInstance()->getCurrentStack()->top());
        if (integer == 0) throw CommandException("Stack top must be an Integer");
        int size = (int) integer->value();
        if ((size >= MIN_VISIBLE_STACK_SIZE) && (size <= MAX_VISIBLE_STACK_SIZE)) {
            Context::getInstance()->getParameters()->setVisibleStackSize(size);
        } else {
            if (size < MIN_VISIBLE_STACK_SIZE) {
                Context::getInstance()->getParameters()->setVisibleStackSize(MIN_VISIBLE_STACK_SIZE);
            } else {
                Context::getInstance()->getParameters()->setVisibleStackSize(MAX_VISIBLE_STACK_SIZE);
            }
        }
        Context::getInstance()->getParameters()->setVisibleStackSize(size);
        Context::getInstance()->getCurrentStack()->pop();
    }

    void VisibleStackSizeParameterCommand::apply(Parameters* parameters) const {
        // vide
    }

    const Memento* VisibleStackSizeParameterCommand::createMemento() const throw (CommandException) {
        if (Context::getInstance()->getCurrentStack()->size() == 0) throw CommandException("Empty stack");
        const Integer* integer = dynamic_cast<const Integer*> (Context::getInstance()->getCurrentStack()->top());
        if (integer == 0) throw CommandException("Stack top must be an Integer");
        return new VisibleStackSizeParameterMemento(clone(), integer->clone(), Context::getInstance()->getParameters()->getVisibleStackSize());
    }

    void VisibleStackSizeParameterCommand::restoreFromMemento(const Memento* memento) const throw (MementoException) {
        const VisibleStackSizeParameterMemento* visibleStackSizeParameterMemento = dynamic_cast<const VisibleStackSizeParameterMemento*> (memento);
        if (visibleStackSizeParameterMemento == 0) {
            std::string str = "Bad Memento type, expected : VisibleStackSizeParameterMemento, was ";
            str += typeid (*memento).name();
            throw MementoException(str);
        }
        Context::getInstance()->getParameters()->setVisibleStackSize(visibleStackSizeParameterMemento->_visibleStackSize);
        Context::getInstance()->getCurrentStack()->push(visibleStackSizeParameterMemento->_integer);
    }
}
